#include "sr2valhelper.h"
#include <iostream>

namespace cores
{
    namespace datas
    {
        SRData::SRData() {}

        SRData::~SRData() {}

        /**
         * @brief 高位在前，低位在后取位的值，位值为1时返回true，否则返回false
         */
        bool SRData::bitIsOn(const uint8_t *buffer, const int &len, int index)
        {
            auto m = index / 8;
            auto n = index % 8;
            if (m >= len)
                return false;
            auto value = 1 << (7 - n);
            if ((buffer[m] & value) == value)
                return true;

            return false;
        }

        /*
                      1
                * * * * * * *
                *           *
            2   *           *  7
                *     3     *
                * * * * * * *
                *           *
            4   *           *  6
                *           *
                * * * * * * *
                      5
        */

        map<string, char> SRNumData::_numMap = {
            {"1101111", '0'}, /* 0 */
            {"0000011", '1'}, /* 1 */
            {"1011101", '2'}, /* 2 */
            {"1010111", '3'}, /* 3 */
            {"0110011", '4'}, /* 4 */
            {"1110110", '5'}, /* 5 */
            {"1111110", '6'}, /* 6 */
            {"1000011", '7'}, /* 7 */
            {"1111111", '8'}, /* 8 */
            {"1110111", '9'}, /* 9 */
            {"0010000", '-'}  /* - */  
        };

        SRNumData::SRNumData(const vector<int> &index)
            : SRData()
            , _indexs{index.begin(), index.end()}
        {
        }

        SRNumData::~SRNumData()
        {
        }

        bool SRNumData::toChar(const uint8_t *buffer, const int &len, char &value)
        {
            string result;
            for (auto &i : _indexs)
            {
                if (bitIsOn(buffer, len, i))
                    result.push_back('1');
                else
                    result.push_back('0');
            }

            if (_numMap.count(result) == 0)
                return false;

            value = _numMap[result];
            return true;
        }

        SRPtData::SRPtData(const int &index)
            : SRData()
            , _index(index)
        {
        }

        SRPtData::~SRPtData()
        {
        }

        bool SRPtData::toChar(const uint8_t *buffer, const int &len, char &value)
        {
            if (bitIsOn(buffer, len, _index) == false)
                return false;

            value = '.';
            return true;
        }

        SR2ValHelper::SR2ValHelper(const uint32_t &screenNumber_)
            : _screenNumber(screenNumber_)
        {
            SR2ValueManager::getInstance()->registerSR2ValueHelper(_screenNumber, this);
        }

        SR2ValHelper::SR2ValHelper(const string &screenModel_)
            : _screenModel(screenModel_)
        {
            SR2ValueManager::getInstance()->registerSR2ValueHelper(_screenModel, this);
        }

        SR2ValHelper::~SR2ValHelper()
        {
            if (_screenNumber > 0)
                SR2ValueManager::getInstance()->unregisterSR2ValueHelper(_screenNumber, this);

            if (!_screenModel.empty())
                SR2ValueManager::getInstance()->unregisterSR2ValueHelper(_screenModel, this);

            for (auto &value : _amounts)
            {
                delete value;
            }
            _amounts.clear();

            for (auto &value : _volumes)
            {
                delete value;
            }
            _volumes.clear();

            for (auto &value : _prices)
            {
                delete value;
            }
            _prices.clear();
        }

        // SR2ValHelper *SR2ValHelper::getInstance(const uint32_t &screenNumber_)
        // {
        //     if (_instancesByScreenNumber.count(screenNumber_) == 0)
        //         return nullptr;

        //     return _instancesByScreenNumber[screenNumber_];
        // }

        // SR2ValHelper *SR2ValHelper::getInstance(const string &screenModel_)
        // {
        //     if (_instancesByScreenModel.count(screenModel_) == 0)
        //         return nullptr;

        //     return _instancesByScreenModel[screenModel_];
        // }

        ScreenValData SR2ValHelper::HexChar2ScreenVal(const uint8_t * buffer, const int &len)
        {
            // 加油金额解析
            bool err_amount = false;            
            auto amount = toString(buffer, len, _amounts, err_amount);
            
            // 加油量解析
            bool err_volume = false;            
            auto volume = toString(buffer, len, _volumes, err_volume);

            // 油单价
            bool err_price = false;
            auto price = toString(buffer, len, _prices, err_price);

            ScreenValData result;
            result.screen_raw_type = err_amount || err_volume || err_price ? 9 : 0;

            try
            {
                result.amount = stof(amount) * 100;
            }
            catch(const std::exception& e)
            {
                std::cerr << e.what() << '\n';
            }
            
            try
            {
                result.volume = stof(volume) * 100;
            }
            catch(const std::exception& e)
            {
                std::cerr << e.what() << '\n';
            }
            
            try
            {
                if (!price.empty())
                    result.price = stof(price) * 100;
                else
                    result.price = 0;
            }
            catch(const std::exception& e)
            {
                std::cerr << e.what() << '\n';
            }
            
            return result;
        }

        string SR2ValHelper::toString(const uint8_t *buffer,
                                      const int &len,
                                      const vector<SRData *> &datas,
                                      bool &err)
        {
            // 解析标记
            auto start = false;
            err = false;
            // 每个数字和小数点
            char value = '\0';

            string result;

            for (auto &data : datas)
            {
                // 解析数字或小数点
                auto r = data->toChar(buffer, len, value);
                if (r == false && start == true)
                {
                    if (dynamic_cast<SRNumData*>(data) != nullptr)
                    {
                        err = true;
                        // 添加错误日志，把数据打印出来

                        break;
                    }
                }
                else if (r == true)
                {
                    if (start == false)
                    {
                        start = true;
                    }
                    result.append(1, value);
                }
            }

            return result;
        }

        SR2ValueManager::SR2ValueManager()
        {
        }

        SR2ValueManager::~SR2ValueManager()
        {
            _instancesByScreenModel.clear();
            _instancesByScreenNumber.clear();
        }

        void SR2ValueManager::registerSR2ValueHelper(const uint32_t &screenNumber_, SR2ValHelper *helper_)
        {
            if (_instancesByScreenNumber.count(screenNumber_) == 0)
            {
                _instancesByScreenNumber[screenNumber_] = helper_;
            }
        }

        void SR2ValueManager::registerSR2ValueHelper(const string &screenModel_, SR2ValHelper *helper)
        {
            if (_instancesByScreenModel.count(screenModel_) == 0)
            {
                _instancesByScreenModel[screenModel_] = helper;
            }
        }

        void SR2ValueManager::unregisterSR2ValueHelper(const uint32_t &screenNumber_, SR2ValHelper *helper_)
        {
            if (_instancesByScreenNumber.count(screenNumber_) == 0 ||
                _instancesByScreenNumber[screenNumber_] != helper_)
                return;

            _instancesByScreenNumber.erase(screenNumber_);
        }

        void SR2ValueManager::unregisterSR2ValueHelper(const string &screenModel_, SR2ValHelper *helper)
        {
            if (_instancesByScreenModel.count(screenModel_) == 0 ||
                _instancesByScreenModel[screenModel_] != helper)
                return;

            _instancesByScreenModel.erase(screenModel_);
        }

        SR2ValueManager *SR2ValueManager::getInstance()
        {
            static SR2ValueManager manager;
            return &manager;
        }

        SR2ValHelper *SR2ValueManager::getSR2ValHelper(const uint32_t &screenNumber_)
        {
            if (_instancesByScreenNumber.count(screenNumber_) == 0)
                return nullptr;

            return _instancesByScreenNumber[screenNumber_];
        }

        SR2ValHelper *SR2ValueManager::getSR2ValHelper(const string &screenModel_)
        {
            if (_instancesByScreenModel.count(screenModel_) == 0)
                return nullptr;

            return _instancesByScreenModel[screenModel_];
        }
    }
}